package ibm.websphere.monitor.common;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;

import ibm.websphere.monitor.bean.JvmInfo;
import ibm.websphere.monitor.bean.ThreadInfo;
import ibm.websphere.monitor.exception.MonitorDaoException;
import ibm.websphere.monitor.page.PageResult;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.jdbc.Work;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;


/**
 * <pre>
 * @Description hibanate的daohelper(通用数据库操作接口)实现类
 * </pre>
 *
 * @copyright www.timotai.net
 * @author 这家伙真懒
 * @date 2016-1-12
 */

public class HibernateDaoHelper<T> extends HibernateDaoSupport implements IDaoHelper<T> {
    private Logger logger = Logger.getLogger(getClass());
    private Class<T> entityClass;

    public HibernateDaoHelper() {
        entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    @Autowired
    public void setMySessionFactory(SessionFactory sessionFactory) {
        super.setSessionFactory(sessionFactory);
    }

    /**
     * <pre>
     *  保存方法
     * </pre>
     *
     * @param obj 实体对象
     */
    public void save(T obj) {
        getHibernateTemplate().save(obj);
    }

    /**
     * <pre>
     * 更新方法
     * </pre>
     *
     * @param obj 实体对象
     */
    public void update(T obj) {
        getHibernateTemplate().update(obj);
    }

    /**
     * <pre>
     * 保存或更新方法
     * </pre>
     *
     * @param obj 实体对象
     */
    public void saveOrUpdate(T obj) {
        this.getHibernateTemplate().clear();
        getHibernateTemplate().saveOrUpdate(obj);
    }

    /**
     * <pre>
     * 删除指定的对象，该对象只包含主键即可
     * </pre>
     *
     * @param obj 实体对象
     */
    public void delete(T obj) {
        getHibernateTemplate().delete(obj);
    }

    /**
     * <pre>
     * 	根据对象ID删除该对象
     * </pre>
     *
     * @param id
     */
    public void delete(Long id) {
        delete(load(id));
    }

    /**
     * <pre>
     * 	根据对象ID加载该对象
     * </pre>
     * <p/>
     * get/load 区别：
     * get 是查一次数据库，如果不存在，会返回NULL
     * load 是走缓存，如果不存在，会抛出ObjectNotFondException.
     *
     * @param id
     * @return
     */
    public T load(Long id) {
        return (T) getHibernateTemplate().load(entityClass, id);
    }

    /**
     * <pre>
     * 	根据对象ID加载该对象
     * </pre>
     *
     * @param id
     * @return
     */
    public T get(Long id) {
        return (T) getHibernateTemplate().get(entityClass, id);
    }

    /**
     * <pre>
     * 	根据实体名查询该对象的所有信息
     * </pre>
     *
     * @return
     */
    public List<T> findAll() {
        return find("from " + entityClass.getSimpleName());
    }

    @SuppressWarnings("rawtypes")
    public List<T> findAll(Class clazz) {
        this.entityClass = clazz;
        return findAll();
    }


    /**
     * <pre>
     *  根据实体名和条件查询该对象的所有信息
     * </pre>
     *
     * @param entityName 实体名
     * @param condition  查询的条件
     * @return
     */
    public List<T> findByCondition(String entityName, String condition) {
        return getHibernateTemplate().find("from " + entityName + " " + condition);
    }


    /**
     * <pre>
     * 执行自定义sql时调用，需要实现Work接口。
     * </pre>
     */
    public void doWork(Work w) {
        this.getSession().doWork(w);
    }

    /**
     * <pre>
     * 使用spring提供的 hibernate 模板处理事务
     * </pre>
     *
     * @param action 事务处理回调
     */
    protected final T execute(HibernateCallback action) {
        return (T) this.getHibernateTemplate().execute(action);
    }


    /**
     * <pre>
     * 	根据条件查询出分页的内容
     * </pre>
     *
     * @param condition
     * @param offset
     * @param max
     * @return
     */
    public List<T> findByCondition(final String condition, final int offset, final int max) {
        HibernateCallback callback = new HibernateCallback() {
            List<?> list = null;

            @SuppressWarnings("unchecked")
            public Object doInHibernate(Session session)
                    throws HibernateException, SQLException {
                // TODO Auto-generated method stub
                Query query = session.createQuery(condition);
                if (offset >= 0 && max >= 0) {
                    query.setFirstResult(offset);
                    query.setMaxResults(max);
                }
                list = query.list();
                if (list == null) list = new ArrayList();
                return list;
            }
        };
        return (List<T>) execute(callback);
    }

    @Override
    public HashMap<String, Double> findNoByMonthSqlCount(String condition) {
        return null;
    }


    public List<Object> findSqlClass(final String sql) {
        final List<Object> flowInfoAll = new ArrayList<Object>();
        Session session = getSession();
        try {
            session.beginTransaction();
            session.doWork(
                    //定义一个匿名类，实现了Work接口
                    new Work() {
                        public void execute(Connection connection) throws SQLException {
                            //经由过程JDBC API执行SQL语句
                            PreparedStatement ps = connection.prepareStatement(sql);
                            ResultSet results = ps.executeQuery();
                            try {
                                ResultSetMetaData metadata = results.getMetaData();
                                int cols = metadata.getColumnCount();
                                String resultRow = "";
                                for (int i = 1; i < cols; i++) {
                                    resultRow += metadata.getColumnName(i) + ";";
                                }
                                System.out.println(resultRow);
                                List resultList = new ArrayList();
                                while (results.next()) {
                                    resultList.clear();
                                    for (int i = 1; i <= cols; i++) {
                                        try {
//                                            resultRow += results.getString(i) + ";";
                                            resultList.add(results.getString(i));
                                        } catch (NullPointerException e) {
                                            System.out.println(e.getMessage());
                                        }
                                    }
                                    Object object = operationObject(resultList);
                                    flowInfoAll.add(object);
                                }
                            }finally {
                                doClose(null, ps, results);
                            }
                        }
                    }
            );
//            session.getTransaction().commit();
//            session.close();
        } catch (Exception ex) {
            logger.error(ex, ex);
        } finally {
            this.doClose(session, null, null);
        }
        return flowInfoAll;
    }


    public Object operationObject(List resultRow){
        String calssName = "";
        Object objectClass = null;
        if (entityClass.getName().equals(JvmInfo.class.getName())) {
            calssName = "ibm.websphere.monitor.bean.JvmInfo";
            objectClass = (Object)new JvmInfo();
        }else{
            calssName = "ibm.websphere.monitor.bean.ThreadInfo";
            objectClass = (Object) new ThreadInfo();
        }

        Class<?> objectInfo = null;
        try{
            objectInfo = Class.forName(calssName);
        }catch (Exception e) {
            e.printStackTrace();
        }
        Constructor<?> cons[] = objectInfo.getConstructors();
        try{
            objectClass = cons[0].newInstance(resultRow);
        }catch (Exception e) {
            e.printStackTrace();
        }
        return objectClass;
    }

    protected void doClose(Session session, Statement stmt, ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
                rs = null;
            } catch (Exception ex) {
                rs = null;
                logger.error(ex, ex);
                ex.printStackTrace();
            }
        }
        // Statement对象关闭时,会自动释放其管理的一个ResultSet对象
        if (stmt != null) {
            try {
                stmt.close();
                stmt = null;
            } catch (Exception ex) {
                stmt = null;
                logger.error(ex, ex);
                ex.printStackTrace();
            }
        }
//      当Hibernate的事务由Spring接管时,session的关闭由Spring管理.不用手动关闭
//      if(session != null){
//          session.close();
//      }
    }

    /**
     * <pre>
     * 	根据条件查询出分页的内容
     * </pre>
     *
     * @param condition
     * @return
     */
    public int findBySqlCount(final String condition) {
        final List<Integer> flowInfoAll = new ArrayList<Integer>();
        doWork(new Work() {
            public void execute(Connection conn) {
                Statement stat = null;
                ResultSet rs = null;
                try {
                    stat = conn.createStatement();
                    rs = stat.executeQuery(condition);

                    while (rs.next()) {
                        flowInfoAll.add(rs.getInt(1));
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                } finally {
                    if (rs != null) {
                        try {
                            rs.close();
                            stat.close();
                            conn.close();
                        } catch (Exception ex) {

                        }
                    }
//					 conn.close();
                }
            }
        });
        return flowInfoAll.get(0);
    }

    /**
     * @param crits
     * @param order
     * @param offset
     * @param maxResults
     * @return
     * @throws MonitorDaoException
     */
    @SuppressWarnings("unchecked")
    public PageResult<T> findPageResult(final Criterion[] crits, final Order order,
                                        final int offset, final int maxResults)
            throws MonitorDaoException {
        T result = execute(new HibernateCallback() {
            public Object doInHibernate(Session session)
                    throws HibernateException, SQLException {
                try {
                    Criteria crit = session.createCriteria(entityClass);
                    Criteria countCrit = session.createCriteria(entityClass);

                    logger.info("findPageResult offset ====" + offset);
                    logger.info("findPageResult maxResults ====" + maxResults);

                    if (offset >= 0 && maxResults >= 0) {
                        crit.setFirstResult(offset);
                        crit.setMaxResults(maxResults);
                    }
                    if (crits != null) {
                        for (Criterion criterion : crits) {
                            if (criterion != null) {
                                crit.add(criterion);
                                countCrit.add(criterion);
                            }
                        }
                    }
                    if (order != null) {
                        crit.addOrder(order);
                    }

                    List<T> data = (List<T>) crit.list();//

                    logger.info("findPageResult size ====" + data != null ? data.size() : "null");

                    Integer numberObjects = (Integer) countCrit.setProjection(Projections.rowCount()).uniqueResult();

                    logger.info("findPageResult count ====" + numberObjects != null ? numberObjects : "null");
//					if (rowCountList.size() > 0) {
//						numberObjects = Integer.parseInt(rowCountList.get(0).toString());
//					}
                    return new PageResult<T>(data, numberObjects);
                } catch (Exception ex) {
                    ex.printStackTrace();
                    return new MonitorDaoException("查询分页记录时发生异常：" + ex.getMessage());
                }
            }
        });
        if (result instanceof MonitorDaoException) {
            throw (MonitorDaoException) result;
        } else {
            return (PageResult<T>) result;
        }
    }

    /**
     * @param crit
     * @param critCount
     * @param offset
     * @param maxResults
     * @return
     * @throws MonitorDaoException
     */
    @SuppressWarnings("unchecked")
    public PageResult<T> findPageResult(final Criteria crit, final Criteria critCount,
                                        final int offset, final int maxResults)
            throws MonitorDaoException {
        T result = execute(new HibernateCallback() {
            public Object doInHibernate(Session session)
                    throws HibernateException, SQLException {
                try {
                    if (offset >= 0 && maxResults >= 0) {
                        crit.setFirstResult(offset);
                        crit.setMaxResults(maxResults);
                    }
                    List<T> data = (List<T>) crit.list();//
                    Integer numberObjects = (Integer) critCount.setProjection(Projections.rowCount()).uniqueResult();
                    return new PageResult<T>(data, numberObjects);
                } catch (Exception ex) {
                    ex.printStackTrace();
                    return new MonitorDaoException("查询分页记录时发生异常：" + ex.getMessage());
                }
            }
        });
        if (result instanceof MonitorDaoException) {
            throw (MonitorDaoException) result;
        } else {
            return (PageResult<T>) result;
        }
    }


    /**
     * @param clazz
     * @param crits
     * @param order
     * @param offset
     * @param maxResults
     * @return
     * @throws MonitorDaoException
     */
    @SuppressWarnings("unchecked")
    public PageResult<T> findPageResult(Class clazz, final Criterion[] crits, final Order order,
                                        final int offset, final int maxResults)
            throws MonitorDaoException {
        this.entityClass = clazz;
        return this.findPageResult(crits, order, offset, maxResults);
    }


    public List<T> find(String hql) {
        // TODO Auto-generated method stub
        return (List<T>) getHibernateTemplate().find(hql);
    }

    public List<Object[]> findHql(String hql) {
        return (List<Object[]>) getHibernateTemplate().find(hql);
    }


    /**
     * 根据对象名和对象属性查询数据
     *
     * @param propertyName
     * @param value
     * @return 实体对象列表
     */
    @SuppressWarnings("unchecked")
    public List<T> findByProperty(String propertyName, Object value) {

        try {
            String hql = "FROM " + entityClass.getSimpleName() + " as o WHERE o." + propertyName + " = ? ";
            Query queryObject = getSession().createQuery(hql);
            queryObject.setParameter(0, value);

            return queryObject.list();
        } catch (RuntimeException re) {
            re.printStackTrace();
            throw re;
        } finally {
        }
    }


    /**
     * 根据对象名和对象属性查询数据
     *
     * @param propertyName
     * @param value
     * @return 实体对象列表
     */
    @SuppressWarnings("unchecked")
    public List<T> findByProperty(String propertyName, Object value, String orderByName) {

        try {
            String hql = "FROM " + entityClass.getSimpleName() + " as o WHERE o." + propertyName + " = ? ORDER BY " + orderByName + " DESC";
            Query queryObject = getSession().createQuery(hql);
            queryObject.setParameter(0, value);

            return queryObject.list();
        } catch (RuntimeException re) {
            System.out.println(re.getMessage());
            throw re;
        } finally {
        }
    }


    /**
     * 根据对象名和对象属性查询数据
     *
     * @param propertyName
     * @param value
     * @return 实体对象列表
     */
    @SuppressWarnings("unchecked")
    public List<T> findByProperty(Class clazz, String propertyName, Object value, String orderByName) {
        this.entityClass = clazz;
        return this.findByProperty(propertyName, value, orderByName);
    }


    public T findOneByProperty(String propertyName, Object value) {
        List<T> list = findByProperty(propertyName, value);
        return list != null && list.size() > 0 ? list.get(0) : null;
    }

    public T findOneByProperty(Class clazz, String propertyName, Object value) {
        this.entityClass = clazz;
        return findOneByProperty(propertyName, value);
    }


    public List<T> findByExample(T object) {
        // TODO Auto-generated method stub
        return (List<T>) getHibernateTemplate().findByExample(object);
    }


    public T findOneByExample(T object) {
        List<T> list = findByExample(object);
        return list != null && list.size() > 0 ? list.get(0) : null;
    }


    public Class<T> getEntityClass() {
        return entityClass;
    }
}
